using System;
using System.Data;
using System.Threading;
using Gdk;
using Gtk;
using kedhlow;
using Mono.Unix;

namespace kedhlow
{
	public partial class MainWindow : Gtk.Window
	{
		Util utils;
		KDB dbc;
		Gtk.ListStore collListStore;
		Gtk.ListStore itemListStore;
		Gtk.ListStore quickSearchHistoryListStore;
		Gtk.ListStore mostViewedItemsListStore;
		Gtk.ListStore itemMetaDataListStore;
		Gtk.ListStore starredItemsListStore;
		bool StartupCompleted;
		Thread thd;
		
		public MainWindow (KDB dbin) : base(Gtk.WindowType.Toplevel)
		{	
			try
			{
				StartupCompleted = false;
				Build ();
				dbc = dbin; dbin = null;
				utils = new Util();
				itemInfoNotebook.Page = 0;
				itemTextView.Buffer = utils.DefineTextTags(itemTextView.Buffer);
				
				//Collections list
				collListStore = dbc.AllCollections();
				collectionsTree.AppendColumn(Catalog.GetString("Collections"), new Gtk.CellRendererText(), "text", 1);
				collectionsTree.SearchColumn = 1;
				collectionsTree.Selection.Changed += new System.EventHandler(collectionsTree_selection_changed);
				collectionsTree.Model = collListStore;
				collectionsTree.ButtonPressEvent += new ButtonPressEventHandler(collectionsTreeButtonPressed);
				
				//Items list
				itemListStore = dbc.AllItemsInCollection(0);
				itemsTree.AppendColumn(Catalog.GetString("Item"), new Gtk.CellRendererText(), "text", 2);
				itemsTree.AppendColumn(Catalog.GetString("Last changed"), new Gtk.CellRendererText(), "text", 3);
				itemsTree.SearchColumn = 2;
				itemsTree.Selection.Changed += new System.EventHandler(itemsTree_selection_changed);
				itemsTree.Model = itemListStore;
				itemsTree.ButtonPressEvent += new ButtonPressEventHandler(itemsTreeButtonPressed);
				StartupCompleted = true;
				
				//Quick search history
				quickSearchHistoryListStore = new ListStore(typeof(string));
				quickSearchHistoryTree.AppendColumn(null, new Gtk.CellRendererText(), "text", 0);
				quickSearchHistoryTree.SearchColumn = 0;
				quickSearchHistoryTree.Selection.Changed += new System.EventHandler(quickSearchHistoryTree_selection_changed);
				quickSearchHistoryTree.Model = quickSearchHistoryListStore;
				
				//Most viewed items
				RefreshTopViewed();
				mostViewedItemsTree.AppendColumn(null, new Gtk.CellRendererText(), "text", 1);
				mostViewedItemsTree.SearchColumn = 1;
				mostViewedItemsTree.Selection.Changed += new System.EventHandler(mostViewedItemsTree_selection_changed);
				
				//Related items
				relatedItemsTree.AppendColumn(Catalog.GetString("Collection"), new Gtk.CellRendererText(), "text", 1);
				relatedItemsTree.AppendColumn(Catalog.GetString("Item"), new Gtk.CellRendererText(), "text", 2);
				relatedItemsTree.AppendColumn(Catalog.GetString("Relevance"), new Gtk.CellRendererText(), "text", 3);
				relatedItemsTree.SearchColumn = 2;
				
				//Starred items
				starredItemsTree.AppendColumn(null, new Gtk.CellRendererText(), "text", 1);
				starredItemsTree.SearchColumn = 1;
				starredItemsTree.Selection.Changed += new System.EventHandler(starredItemsTree_selection_changed);
				RefreshStarredItemsTree(); //Reload the starred items list
				
				//Item metadata
				itemMetaTree.AppendColumn(null, new Gtk.CellRendererText(), "text", 0);
				itemMetaTree.AppendColumn(null, new Gtk.CellRendererText(), "text", 1);
				itemMetaDataListStore = new ListStore(typeof(string));
			}
			catch (Exception excp)
			{
				Console.WriteLine(Catalog.GetString("Fatal error loading application") + ":");
				Console.WriteLine(excp.Message);
				Console.WriteLine(excp.StackTrace);
			}
		}
		protected void OnDeleteEvent (object sender, DeleteEventArgs a)
		{
			Application.Quit();
			a.RetVal = true;
		}
		protected virtual void OnExitActionActivated (object sender, System.EventArgs e)
		{
			OnDeleteEvent(sender, new DeleteEventArgs());
		}
		
		//Menu (de)sensitise methods
		protected void OnCollectionSelected()
		{
			mnuNewItemAction.Sensitive = true;
			mnuEditCollection.Sensitive = true;
			mnuDeleteCollection.Sensitive = true;
			itemsTree.Sensitive = true;
			txtSearchString.Text = "";
		}
		protected void OnCollectionDeselected()
		{
			mnuNewItemAction.Sensitive = false;
			itemsTree.Sensitive = false;
			mnuEditCollection.Sensitive = false;
			mnuDeleteCollection.Sensitive = false;
						
			//Clear all items
			if(StartupCompleted) { itemListStore.Clear(); }
			OnItemDeselected();
		}
		protected void OnItemSelected()
		{
			itemInfoNotebook.Sensitive = true;
			mnuEditemAction.Sensitive = true;
			mnuDeleteItemAction.Sensitive = true;
			quickSearchHistoryTree.Selection.UnselectAll();
		}
		protected void OnItemDeselected()
		{
			itemInfoNotebook.Sensitive = false;
			mnuEditemAction.Sensitive = false;
			mnuDeleteItemAction.Sensitive = false;
			itemTextView.Buffer.Clear();
			lblItemTitle.Text = "";
			
			if(StartupCompleted) { itemMetaDataListStore.Clear(); }
			
			if(thd != null)
			{
				if(thd.ThreadState == ThreadState.Running)
				{
					thd.Abort();
					mwStatusBar.Pop(mwStatusBar.GetContextId("LoadingLinkedItems"));
				}
			}
			relatedItemsTree.Model = null;
			imgStar.Pixbuf = null;
			//relatedItemsTree.ShowAll();
		}
		
		//Collections methods
		[GLib.ConnectBefore]
		private void collectionsTreeButtonPressed(object obj, ButtonPressEventArgs args)
		{	
			if(args.Event.Button == 1)
			{
				if(args.Event.Type == EventType.TwoButtonPress)
				{ OnMnuNewCollectionActivated(obj, null); }
			}
			else if(args.Event.Button == 3)
			{
				Menu m = new Menu();
				if(utils.TreeviewHasSelection(collectionsTree))
				{
					MenuItem editCollectionContext = new MenuItem(Catalog.GetString("Edit"));
					MenuItem deleteCollectionContext = new MenuItem(Catalog.GetString("Delete"));
					editCollectionContext.ButtonPressEvent +=  new ButtonPressEventHandler(OnMnuEditCollectionActivated);
					deleteCollectionContext.ButtonPressEvent +=  new ButtonPressEventHandler(OnMnuDeleteCollectionActivated);
					m.Add(editCollectionContext);
					m.Add(deleteCollectionContext);	
				}
				else
				{
					MenuItem addCollectionContext = new MenuItem(Catalog.GetString("New"));
					addCollectionContext.ButtonPressEvent +=  new ButtonPressEventHandler(OnMnuNewCollectionActivated);
					m.Add(addCollectionContext);
				}
				m.ShowAll();
				m.Popup();
			}
		}
		protected void collectionsTree_selection_changed(object sender, System.EventArgs e)
		{
			TreeIter iter; TreeModel model;
		    if(collectionsTree.Selection.GetSelected(out model, out iter))
		    {
				itemListStore = dbc.AllItemsInCollection((int) model.GetValue (iter, 0));
				itemsTree.Model = itemListStore;
				OnCollectionSelected();
		    }
			else
			{
				OnCollectionDeselected();
			}
		}
		protected virtual void OnMnuNewCollectionActivated (object sender, System.EventArgs e)
		{
			addEditCollection newCollection = new addEditCollection();
			ResponseType rsp = (ResponseType) newCollection.Run();
			if(rsp == ResponseType.Ok)
			{
				int newID = dbc.AddCollection(newCollection.CollectionTitle);
				collListStore.AppendValues(newID,newCollection.CollectionTitle);
				OnCollectionDeselected();
			}
			newCollection.Destroy();
		}	
		protected virtual void OnMnuEditCollectionActivated (object sender, System.EventArgs e)
		{
			TreeIter iter; TreeModel model;
		    if(collectionsTree.Selection.GetSelected(out model, out iter))
		    {
		        int id = (int) model.GetValue (iter, 0);
				addEditCollection editCollection = new addEditCollection(id,dbc);
				ResponseType rsp = (ResponseType) editCollection.Run();
				if(rsp == ResponseType.Ok)
				{
					dbc.EditCollectionByID(id, editCollection.CollectionTitle);
					model.SetValue(iter, 1, editCollection.CollectionTitle);
				}
				editCollection.Destroy();
		    }
		}
		protected virtual void OnMnuDeleteCollectionActivated (object sender, System.EventArgs e)
		{
			TreeIter iter; TreeModel model;
		    if(collectionsTree.Selection.GetSelected(out model, out iter))
		    {
		        int id = (int) model.GetValue (iter, 0);
				dbc.DeleteCollectionById(id);
				collListStore.Remove(ref iter);
				OnCollectionDeselected();
		    }
		}
		
		//Item methods
		[GLib.ConnectBefore]
		private void itemsTreeButtonPressed(object obj, ButtonPressEventArgs args)
		{	
			if(args.Event.Button == 1)
			{
				if(args.Event.Type == EventType.TwoButtonPress)
				{ OnMnuNewItemActionActivated(obj, null); }
			}
			else if(args.Event.Button == 3)
			{
				Menu m = new Menu();
				if(utils.TreeviewHasSelection(itemsTree))
				{
					
					MenuItem editCollectionContext = new MenuItem(Catalog.GetString("Edit"));
					MenuItem deleteCollectionContext = new MenuItem(Catalog.GetString("Delete"));
					editCollectionContext.ButtonPressEvent +=  new ButtonPressEventHandler(OnMnuEditemActionActivated);
					deleteCollectionContext.ButtonPressEvent +=  new ButtonPressEventHandler(OnMnuDeleteItemActionActivated);
					m.Add(editCollectionContext);
					m.Add(deleteCollectionContext);	
				}
				else
				{
					MenuItem addCollectionContext = new MenuItem(Catalog.GetString("New"));
					addCollectionContext.ButtonPressEvent +=  new ButtonPressEventHandler(OnMnuNewItemActionActivated);
					m.Add(addCollectionContext);			
				}
				m.ShowAll();
				m.Popup();
			}
		}
		protected void itemsTree_selection_changed(object sender, System.EventArgs e)
		{
			TreeIter iter; TreeModel model; //Store selected item
			if(itemsTree.Selection.GetSelected(out model, out iter))
			{
				int id = (int) model.GetValue (iter, 0);
				LoadItem(id);
		    }
			else
			{
				OnItemDeselected();
			}
		}		
		protected void LoadItem(int ItemID)
		{
			LoadItem(ItemID,true);
		}
		protected void LoadItem(int itemID, bool GetItemData)
		{
			// Generate automatically linked items list. Start this first so its thread can run
			GLib.Timeout.Add(1000,new GLib.TimeoutHandler( delegate() { this.ShowAll(); return true; } ));
			mwStatusBar.Push(mwStatusBar.GetContextId("LoadingLinkedItems"),Mono.Unix.Catalog.GetString("Generating links"));
			thd = new Thread(delegate()
			{
				Gtk.ListStore nls = utils.GetRelatedItems(itemID,dbc);
				Application.Invoke(
						delegate
						{
							relatedItemsTree.Model = nls;
							relatedItemsTree.ShowAll();
							lblLinkedWordsList.LabelProp = utils.LinkedWordsListString;
							mwStatusBar.Pop(mwStatusBar.GetContextId("LoadingLinkedItems"));
						});
			});
			thd.Start();
			
			RefreshTopViewed();
			if(GetItemData)
			{
				byte[] itemdata = dbc.GetItemData(itemID);
				if(itemdata != null)
				{
					lblItemTitle.Text = dbc.GetItemTitle(itemID);
					itemTextView.Buffer = utils.DeserialiseTextBuffer(itemdata,itemTextView.Buffer.TagTable);
					dbc.ItemViewCountIncr(itemID);
				}
			}

			LoadItemMetaData(itemID);
			LoadItemStarImage(itemID);
			OnItemSelected();
			
		}
		protected void LoadItemMetaData(int itemID)
		{
			itemMetaDataListStore = dbc.ItemMetaData(itemID);
			itemMetaTree.Model = itemMetaDataListStore;
			itemMetaTree.ShowAll();
		}
		protected virtual void OnMnuNewItemActionActivated (object sender, System.EventArgs e)
		{
			TreeIter iter; TreeModel model;
		    if(collectionsTree.Selection.GetSelected(out model, out iter))
		    {
				AddEditItem addNew = new AddEditItem();
				ResponseType rsp = (ResponseType) addNew.Run();

				if(rsp == ResponseType.Ok)
				{
			        int colid = (int) model.GetValue (iter, 0);
					int newid = dbc.AddItem(colid,addNew.ItemTitle,addNew.ItemData,addNew.ItemPlainText,addNew.SaveDateTime.ToString());
					TreeIter iterl = itemListStore.AppendValues(newid,colid,addNew.ItemTitle,addNew.SaveDateTime.ToString());
					itemsTree.Selection.SelectIter(iterl);
					//LoadItem(newid, false);
				}
				addNew.Destroy();
			}
			else
			{
				OnMnuNewCollectionActivated(sender, null);
			}
		}
		protected virtual void OnMnuEditemActionActivated (object sender, System.EventArgs e)
		{
			TreeIter iter; TreeModel model;
		    if(itemsTree.Selection.GetSelected(out model, out iter))
		    {
		        int itemid = (int) model.GetValue (iter, 0);
				AddEditItem editItem = new AddEditItem(itemid, dbc);
				ResponseType rsp = (ResponseType) editItem.Run();
	
				if(rsp == ResponseType.Ok)
				{
					dbc.EditItem(itemid,editItem.ItemTitle,editItem.ItemData,editItem.ItemPlainText,editItem.SaveDateTime.ToString());
					model.SetValue(iter, 2, editItem.ItemTitle);
					model.SetValue(iter, 3, editItem.SaveDateTime.ToString());
					itemTextView.Buffer = utils.DeserialiseTextBuffer(editItem.ItemData,itemTextView.Buffer.TagTable);
					LoadItem(itemid);					
				}
				editItem.Destroy();
			}
		}
		protected virtual void OnMnuDeleteItemActionActivated (object sender, System.EventArgs e)
		{
			TreeIter iter; TreeModel model;
		    if(itemsTree.Selection.GetSelected(out model, out iter))
		    {
		        int itemid = (int) model.GetValue (iter, 0);
				dbc.DeleteItem(itemid);
				itemListStore.Remove(ref iter);
				itemTextView.Buffer.Clear();
				OnItemDeselected();
			}
		}	
		
		//Quick search methods
		protected virtual void OnBtnSearchItemsClicked (object sender, System.EventArgs e)
		{
			if(txtSearchString.Text.Length>1)
			{
				DoQuickSearch(txtSearchString.Text);
				TreeIter iter;
				quickSearchHistoryTree.Model.GetIterFirst(out iter);
				bool QuickSearchInHistory = false;
				for (int i = 0; i < quickSearchHistoryTree.Model.IterNChildren(); i++)
				{
					if (quickSearchHistoryListStore.GetValue(iter, 0).ToString().ToUpper().Equals(txtSearchString.Text.ToString().ToUpper()))
					{
						QuickSearchInHistory = true;
						break;
					}
					quickSearchHistoryListStore.IterNext(ref iter);
				}
				if(! QuickSearchInHistory) { quickSearchHistoryListStore.AppendValues(txtSearchString.Text); }
			}
		}
		protected void quickSearchHistoryTree_selection_changed(object sender, System.EventArgs e)
		{
			TreeIter iter; TreeModel model;
		    if(quickSearchHistoryTree.Selection.GetSelected(out model, out iter))
		    {
				DoQuickSearch((string) model.GetValue (iter, 0));
		    }
		}
		protected void DoQuickSearch(string SearchString)
		{
			//itemListStore = dbc.SearchAllCollections(txtSearchString.Text);
			itemsTree.Model = itemListStore;
			collectionsTree.Selection.UnselectAll();
			itemsTree.Selection.UnselectAll();
			OnCollectionDeselected();
			OnItemDeselected(); 
			itemsTree.Sensitive = true;
			
			IDataReader reader = dbc.SearchAllCollections(SearchString);
			int cnt = 0;
			while(reader.Read())
			{
				cnt++;
				itemListStore.AppendValues(reader.GetInt32(0),reader.GetInt32(1),reader.GetString(2),reader.GetString(3));
			}
			if(cnt==0) { OnCollectionDeselected(); }
			
		}

		//Top items listing
		protected void RefreshTopViewed()
		{
			mostViewedItemsListStore = dbc.MostViewedItems();
			mostViewedItemsTree.Model = mostViewedItemsListStore;
			mostViewedItemsTree.ShowAll();
		}
		protected void mostViewedItemsTree_selection_changed(object sender, System.EventArgs e)
		{
			TreeIter iter; TreeModel model;
		    if(mostViewedItemsTree.Selection.GetSelected(out model, out iter))
		    {
				collectionsTree.Selection.UnselectAll();
				LoadItem((int) model.GetValue (iter, 0));
		    }
		}

		//Star/unstar methods
		protected virtual void OnimgStarEventBoxButtonPressEvent (object o, Gtk.ButtonPressEventArgs args)
		{
			TreeIter iter; TreeModel model; //Store selected item
			if(itemsTree.Selection.GetSelected(out model, out iter))
			{
				int id = (int) model.GetValue (iter, 0);
				if(dbc.IsItemStarred(id))
				{
					//Unstar
					dbc.UnstarItem(id);					
				}
				else
				{
					//Star
					dbc.StarItem(id);
				}
				RefreshStarredItemsTree();
				LoadItemStarImage(id);
				LoadItemMetaData(id);
		    }
		}
		protected void LoadItemStarImage(int itemID)
		{
			//Check star status
			if(dbc.IsItemStarred(itemID))
			{
				imgStar.Pixbuf = Pixbuf.LoadFromResource ("kedhlow.star_on.png");
			}
			else
			{
				imgStar.Pixbuf = Pixbuf.LoadFromResource ("kedhlow.star_off.png");
			}
		}
		protected void RefreshStarredItemsTree()
		{
			starredItemsListStore = dbc.AllStarredItems();
			starredItemsTree.Model = starredItemsListStore;
			starredItemsTree.ShowAll();
		}
		protected void starredItemsTree_selection_changed(object sender, System.EventArgs e)
		{
			TreeIter iter; TreeModel model;
		    if(starredItemsTree.Selection.GetSelected(out model, out iter))
		    {
				collectionsTree.Selection.UnselectAll();
				LoadItem((int) model.GetValue (iter, 0));
		    }
		}
	}
}